package art.client.widgets;

import java.util.Date;
import java.util.List;

import art.client.ClientUtils;
import art.client.services.ArtService;
import art.client.services.ArtServiceAsync;
import art.client.services.UserService;
import art.client.services.UserServiceAsync;
import art.shared.entities.ArtShared;
import art.shared.entities.GenreShared;
import art.shared.entities.LoginInfo;
import art.shared.entities.RatingShared;
import art.shared.entities.UserShared;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.NumberCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;

public class TableColumnFactory {

	private static TableColumnFactory factory = null;

	protected TableColumnFactory() {
	}

	public static TableColumnFactory getFactory() {
		if (factory == null) {
			factory = new TableColumnFactory();
		}
		return factory;
	}

	public TextColumn<ArtShared> getArtTitleColumn() {
		TextColumn<ArtShared> column = new TextColumn<ArtShared>() {
			@Override
			public String getValue(ArtShared object) {
				return object.getTitle();
			}
		};
		column.setSortable(true);
		return column;
	}

	public Column<ArtShared, Date> getArtUploadedOnColumn() {
		DateCell dateCell = new DateCell();
		Column<ArtShared, Date> column = new Column<ArtShared, Date>(dateCell) {
			@Override
			public Date getValue(ArtShared object) {
				return object.getUploadedOn();
			}
		};
		column.setSortable(true);
		return column;
	}

	public TextColumn<ArtShared> getArtCreatorColumn(
			final List<UserShared> users) {
		TextColumn<ArtShared> column = new TextColumn<ArtShared>() {
			@Override
			public String getValue(ArtShared object) {
				for (UserShared user : users) {
					if (user.getId() == object.getCreatorId()) {
						if (user.getName() != null && !user.getName().isEmpty()) {
							return user.getName();
						}
					}
				}
				return "-";
			}
		};
		column.setSortable(true);
		return column;
	}

	public TextColumn<ArtShared> getArtGenreColumn(
			final List<GenreShared> genres) {
		TextColumn<ArtShared> column = new TextColumn<ArtShared>() {
			@Override
			public String getValue(ArtShared object) {
				if (object.getGenre() == null) {
					return "";
				} else {
					GenreShared genre = object.getGenre();
					String columnText = "";
					while (genre != null) {
						columnText = genre.getName() + "/" + columnText;
						genre = ClientUtils.getParentGenre(genre, genres);
					}
					return columnText;
				}
			}
		};
		return column;
	}

	public TextColumn<UserShared> getUserNicknameColumn() {
		TextColumn<UserShared> column = new TextColumn<UserShared>() {
			@Override
			public String getValue(UserShared object) {
				return object.getNickname();
			}
		};
		return column;
	}

	public TextColumn<UserShared> getUserNameColumn() {
		TextColumn<UserShared> column = new TextColumn<UserShared>() {
			@Override
			public String getValue(UserShared object) {
				return object.getName();
			}
		};
		return column;
	}

	public TextColumn<UserShared> getUserEmailColumn() {
		TextColumn<UserShared> column = new TextColumn<UserShared>() {
			@Override
			public String getValue(UserShared object) {
				return object.getEmail();
			}
		};
		return column;
	}

	public TextColumn<UserShared> getUserGenderColumn() {
		TextColumn<UserShared> column = new TextColumn<UserShared>() {
			@Override
			public String getValue(UserShared object) {
				if (object.getGender() == null)
					return null;
				return object.getGender().toString();
			}
		};
		return column;
	}

	public Column<UserShared, Date> getUserDateOfBirthColumn() {
		DateCell dateCell = new DateCell();
		Column<UserShared, Date> column = new Column<UserShared, Date>(dateCell) {
			@Override
			public Date getValue(UserShared object) {
				return object.getDateOfBirth();
			}
		};
		return column;
	}

	public Column<UserShared, Number> getUserArtNumColumn() {
		NumberCell numberCell = new NumberCell();
		Column<UserShared, Number> column = new Column<UserShared, Number>(
				numberCell) {
			@Override
			public Number getValue(UserShared object) {
				if (object.getArts() == null) {
					return 0;
				}
				return object.getArts().size();
			}
		};
		return column;
	}

	public Column<UserShared, String> getUserDeleteButtonColumn() {
		ButtonCell buttonCell = new ButtonCell();
		Column<UserShared, String> buttonColumn = new Column<UserShared, String>(
				buttonCell) {
			@Override
			public String getValue(UserShared object) {
				return "Delete user";
			}
		};
		buttonColumn.setFieldUpdater(new FieldUpdater<UserShared, String>() {
			public void update(int index, final UserShared object, String value) {
				VerticalPanel panel = new VerticalPanel();
				HorizontalPanel buttonPanel = new HorizontalPanel();
				Button saveButton = new Button("Yes");
				Button cancelButton = new Button("Cancel");
				buttonPanel.add(saveButton);
				buttonPanel.add(cancelButton);
				panel.add(new Label("Are you sure you want to remove user?"));
				panel.add(buttonPanel);
				final DecoratedPopupPanel popup = new DecoratedPopupPanel(false);
				popup.setGlassEnabled(true);
				popup.center();
				popup.show();
				saveButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						UserServiceAsync userService = GWT
								.create(UserService.class);
						userService.deleteUser(object,
								new AsyncCallback<Boolean>() {

									@Override
									public void onSuccess(Boolean result) {
										if (!result) {
											Window.alert("Error during removing user!");
										}
									}

									@Override
									public void onFailure(Throwable arg0) {
										Window.alert("Error during removing user!");
									}
								});
						popup.hide();
					}
				});
				cancelButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						popup.hide();
					}
				});
			}
		});
		return buttonColumn;
	}

	public Column<ArtShared, String> getArtDownloadColumn(
			final List<UserShared> users) {
		ButtonCell buttonCell = new ButtonCell();
		Column<ArtShared, String> buttonColumn = new Column<ArtShared, String>(
				buttonCell) {
			@Override
			public String getValue(ArtShared object) {
				return "Show art";
			}
		};
		buttonColumn.setFieldUpdater(new FieldUpdater<ArtShared, String>() {
			public void update(int index, ArtShared object, String value) {
				String url = GWT.getHostPageBaseURL()
						+ "artportal/artdownload?artId=" + object.getId();
				Frame frame = new Frame(url);
				frame.getElement().setId("art-frame");
				//frame.setSize("100%", "100%");
				DecoratedPopupPanel popup = new DecoratedPopupPanel(true);
				String userName = null;
				for (UserShared user : users) {
					if (user.getId() == object.getCreatorId()) {
						userName = user.getName();
						break;
					}
				}

				VerticalPanel panel = new VerticalPanel();
				panel.add(new Label("Title: " + object.getTitle()
						+ " Creator: " + (userName == null ? "-" : userName)));
				panel.add(frame);
				panel.getElement().setId("art-frame-panel");
				popup.add(panel);
				popup.getElement().setId("art-popup");
				//popup.setSize("600px", "600px");
				popup.center();
				popup.show();

			}
		});
		return buttonColumn;
	}

	public Column<ArtShared, String> getArtViewReviewsColumn(
			final List<UserShared> users) {
		ButtonCell buttonCell = new ButtonCell();
		Column<ArtShared, String> buttonColumn = new Column<ArtShared, String>(
				buttonCell) {
			@Override
			public String getValue(ArtShared object) {
				return "Show ratings";
			}
		};
		buttonColumn.setFieldUpdater(new FieldUpdater<ArtShared, String>() {
			public void update(int index, ArtShared object, String value) {
				ArtServiceAsync artService = GWT.create(ArtService.class);
				artService.getRatingsOfArt(object.getId(),
						new AsyncCallback<List<RatingShared>>() {

							@Override
							public void onFailure(Throwable arg0) {
								Window.alert("Error during getting ratings!");
							}

							@Override
							public void onSuccess(List<RatingShared> ratings) {
								final DecoratedPopupPanel popup = new DecoratedPopupPanel(
										true);
								VerticalPanel panel = new VerticalPanel();
								for (RatingShared rating : ratings) {
									String userName = null;
									for (UserShared user : users) {
										if (user.getId() == rating
												.getCreatorId()) {
											userName = user.getName();
											break;
										}
									}
									VerticalPanel ratingPanel = new VerticalPanel();
									HorizontalPanel infoPanel = new HorizontalPanel();
									DateTimeFormat format = DateTimeFormat
											.getFormat("yyyy-MM-dd");
									Label addedonLabel = new Label("Added on: "
											+ format.format(rating
													.getCreatedOn()));
									addedonLabel.setStyleName("ratingspopup-addedonlabel");
									infoPanel.add(addedonLabel);
									Label creatorLabel = new Label("Creator: "
											+ (userName == null ? "-"
													: userName));
									creatorLabel.setStyleName("ratingspopup-creatorlabel");
									infoPanel.add(creatorLabel);
									Label ratingLabel = new Label("Rating: "
											+ (rating.getRate() == null ? "-"
													: rating.getRate()));
									ratingLabel.setStyleName("ratingspopup-ratinglabel");
									infoPanel.add(ratingLabel);
									ratingPanel.add(infoPanel);
									Label reviewLabel = new Label("Review:");
									reviewLabel.setStyleName("ratingspopup-reviewlabel");
									ratingPanel.add(reviewLabel);
									Label actualReviewLabel = new Label(rating
											.getReview());
									actualReviewLabel.addStyleName("ratingspopup-actualreviewlabel");
									ratingPanel.add(actualReviewLabel);
									panel.add(ratingPanel);
								}
								ScrollPanel scrollPanel = new ScrollPanel(panel);
								VerticalPanel mainPanel = new VerticalPanel();
								mainPanel.add(scrollPanel);
								Button close = new Button("Close");
								close.addClickHandler(new ClickHandler() {

									@Override
									public void onClick(ClickEvent arg0) {
										popup.hide();

									}
								});
								mainPanel.add(close);
								popup.add(mainPanel);
								popup.center();
								popup.show();
							}
						});

			}
		});
		return buttonColumn;
	}

	public Column<ArtShared, String> getArtAddReviewColumn(
			final List<UserShared> users, final LoginInfo loginInfo) {
		ButtonCell buttonCell = new ButtonCell();
		Column<ArtShared, String> buttonColumn = new Column<ArtShared, String>(
				buttonCell) {
			@Override
			public String getValue(ArtShared object) {
				return "Add rating";
			}
		};
		buttonColumn.setFieldUpdater(new FieldUpdater<ArtShared, String>() {
			@Override
			public void update(int index, final ArtShared object, String value) {
				final DecoratedPopupPanel popup = new DecoratedPopupPanel(false);
				VerticalPanel panel = new VerticalPanel();
				popup.setGlassEnabled(true);
				HorizontalPanel ratingPanel = new HorizontalPanel();
				HorizontalPanel buttonPanel = new HorizontalPanel();
				final ListBox ratingBox = new ListBox();
				ratingBox.addItem("No rating");
				ratingBox.addItem("0");
				ratingBox.addItem("1");
				ratingBox.addItem("2");
				ratingBox.addItem("3");
				ratingBox.addItem("4");
				ratingBox.addItem("5");
				ratingPanel.add(new Label("Rating: "));
				ratingPanel.add(ratingBox);
				panel.add(ratingPanel);
				final TextArea review = new TextArea();
				panel.add(new Label("Write a review: "));
				panel.add(review);
				Button saveButton = new Button("Save");
				Button cancelButton = new Button("Cancel");
				buttonPanel.add(saveButton);
				buttonPanel.add(cancelButton);
				panel.add(buttonPanel);
				saveButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						RatingShared rating = new RatingShared();
						for (UserShared user : users) {
							if (user.getEmail().equals(
									loginInfo.getEmailAddress())) {
								rating.setCreatorId(user.getId());
								break;
							}
						}
						rating.setCreatedOn(new Date());
						rating.setReview(review.getText());
						rating.setArtId(object.getId());
						if (ratingBox.getSelectedIndex() == 0) {
							rating.setRate(null);
						} else {
							rating.setRate(ratingBox.getSelectedIndex() - 1);
						}
						ArtServiceAsync artService = GWT
								.create(ArtService.class);
						artService.addRatingToArt(rating,
								new AsyncCallback<Boolean>() {

									@Override
									public void onSuccess(Boolean result) {
										if (!result) {
											Window.alert("Error during adding rating!");
										}
									}

									@Override
									public void onFailure(Throwable arg0) {
										Window.alert("Error during adding rating!");
									}
								});
						popup.hide();
						object.addRating(rating);
					}
				});
				cancelButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						popup.hide();
					}
				});
				popup.add(panel);
				popup.center();
				popup.show();
			}
		});
		return buttonColumn;
	}

	public Column<ArtShared, String> getArtDeleteColumn(final ArtTable table) {
		ButtonCell buttonCell = new ButtonCell();
		Column<ArtShared, String> buttonColumn = new Column<ArtShared, String>(
				buttonCell) {
			@Override
			public String getValue(ArtShared object) {
				return "Delete art";
			}
		};
		buttonColumn.setFieldUpdater(new FieldUpdater<ArtShared, String>() {
			@Override
			public void update(int index, final ArtShared object, String value) {
				VerticalPanel panel = new VerticalPanel();
				HorizontalPanel buttonPanel = new HorizontalPanel();
				Button saveButton = new Button("Yes");
				Button cancelButton = new Button("Cancel");
				buttonPanel.add(saveButton);
				buttonPanel.add(cancelButton);
				panel.add(new Label("Are you sure you want to remove art?"));
				panel.add(buttonPanel);
				final DecoratedPopupPanel popup = new DecoratedPopupPanel(false);
				popup.setGlassEnabled(true);
				popup.add(panel);
				popup.center();
				popup.show();
				saveButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						ArtServiceAsync artService = GWT
								.create(ArtService.class);
						artService.deleteArt(object.getId(),
								new AsyncCallback<Boolean>() {

									@Override
									public void onSuccess(Boolean result) {
										for (ArtShared art : table.getDataProvider().getList()) {
											if (art.getId() == object.getId()) {
												table.getDataProvider().getList().remove(art);
												break;
											}
										}
										if (!result) {
											Window.alert("Error during removing art!");
										}
									}

									@Override
									public void onFailure(Throwable arg0) {
										Window.alert("Error during removing art!");
									}
								});
						popup.hide();
					}
				});
				cancelButton.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent arg0) {
						popup.hide();
					}
				});
			}
		});
		return buttonColumn;
	}

	public Column<ArtShared, Number> getArtAvgRatingColumn() {
		NumberCell numberCell = new NumberCell();
		Column<ArtShared, Number> column = new Column<ArtShared, Number>(
				numberCell) {
			@Override
			public Number getValue(ArtShared object) {
				return object.getAvgRating();
			}
		};
		column.setSortable(true);
		return column;
	}
}
